JavaScriptã®äžŠè¡ãããã®æŠå¿µãæ¢ãããã«ãã¹ã¬ãããéåæç°å¢ã§ã®ããã©ãŒãã³ã¹ãåäžããã䞊åããŒã¿æ§é æäœã«ã€ããŠè§£èª¬ããŸãããã®å©ç¹ãå®è£ ã®èª²é¡ãå®è·µçãªãŠãŒã¹ã±ãŒã¹ãåŠã³ãŸãã
JavaScriptã®äžŠè¡ãããïŒããã©ãŒãã³ã¹åäžã®ããã®äžŠåããŒã¿æ§é æäœ
çŸä»£ã®JavaScriptéçºãç¹ã«Node.jsç°å¢ãWeb Workerãå©çšãããŠã§ããã©ãŠã¶ã«ãããŠãäžŠè¡æäœãå®è¡ããèœåã¯ãŸããŸãéèŠã«ãªã£ãŠããŸããäžŠè¡æ§ãããã©ãŒãã³ã¹ã«å€§ããªåœ±é¿ãäžããåéã®äžã€ããããŒã¿æ§é ã®æäœã§ãããã®ããã°èšäºã§ã¯ãJavaScriptã«ããã䞊è¡ãããã®æŠå¿µãæãäžããŸããããã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãåçã«åäžãããããšãã§ããã䞊åããŒã¿æ§é æäœã®ããã®åŒ·åãªããŒã«ã§ãã
䞊è¡ããŒã¿æ§é ã®å¿ èŠæ§ãçè§£ãã
çµã¿èŸŒã¿ã®MapãObjectã®ãããªåŸæ¥ã®JavaScriptã®ããŒã¿æ§é ã¯ãæ¬è³ªçã«ã·ã³ã°ã«ã¹ã¬ããã§ããããã¯ãäžåºŠã«äžã€ã®æäœããããŒã¿æ§é ã«ã¢ã¯ã»ã¹ããã倿Žãããã§ããªãããšãæå³ããŸããããã«ããããã°ã©ã ã®åäœã«ã€ããŠã®æšè«ã¯åçŽã«ãªããŸããã以äžã®ãããªã·ããªãªã§ã¯ããã«ããã¯ã«ãªãå¯èœæ§ããããŸãïŒ
- ãã«ãã¹ã¬ããç°å¢ïŒ Web Workerã䜿çšããŠJavaScriptã³ãŒãã䞊åã¹ã¬ããã§å®è¡ããå Žåãè€æ°ã®ã¯ãŒã«ãŒããå
±æã®
Mapã«åæã«ã¢ã¯ã»ã¹ãããšãç«¶åç¶æ ãããŒã¿ã®ç Žæã«ã€ãªããå¯èœæ§ããããŸãã - éåææäœïŒ Node.jsããã©ãŠã¶ããŒã¹ã®ã¢ããªã±ãŒã·ã§ã³ã§å€æ°ã®éåæã¿ã¹ã¯ïŒäŸïŒãããã¯ãŒã¯ãªã¯ãšã¹ãããã¡ã€ã«I/OïŒãæ±ãå Žåãè€æ°ã®ã³ãŒã«ããã¯ãåæã«
Mapã倿Žããããšããäºæž¬äžå¯èœãªåäœãåŒãèµ·ããå¯èœæ§ããããŸãã - 髿§èœã¢ããªã±ãŒã·ã§ã³ïŒ ãªã¢ã«ã¿ã€ã ã®ããŒã¿åæãã²ãŒã éçºãç§åŠã·ãã¥ã¬ãŒã·ã§ã³ãªã©ãéäžçãªããŒã¿åŠçèŠä»¶ãæã€ã¢ããªã±ãŒã·ã§ã³ã¯ã䞊è¡ããŒã¿æ§é ãæäŸããäžŠåæ§ã®æ©æµãåããããšãã§ããŸãã
䞊è¡ãããã¯ãè€æ°ã®ã¹ã¬ãããéåæã³ã³ããã¹ããããããã®ã³ã³ãã³ãã«å®å šã«ã¢ã¯ã»ã¹ããåæã«å€æŽããããã®ã¡ã«ããºã ãæäŸããããšã§ããããã®èª²é¡ã«å¯ŸåŠããŸããããã«ãããæäœã®äžŠåå®è¡ãå¯èœã«ãªããç¹å®ã®ã·ããªãªã§å€§å¹ ãªããã©ãŒãã³ã¹åäžãããããããŸãã
䞊è¡ããããšã¯äœãïŒ
䞊è¡ããããšã¯ãè€æ°ã®ã¹ã¬ãããéåææäœãããŒã¿ã®ç Žæãç«¶åç¶æ ãåŒãèµ·ããããšãªãããã®ã³ã³ãã³ãã«åæã«ã¢ã¯ã»ã¹ã倿Žã§ããããŒã¿æ§é ã§ããããã¯éåžžã以äžã®æ¹æ³ã§å®çŸãããŸãïŒ
- ã¢ãããã¯æäœïŒ åäžã®äžå¯åãªåäœãšããŠå®è¡ãããæäœã§ãæäœäžã«ä»ã®ã¹ã¬ãããå¹²æžã§ããªãããšãä¿èšŒããŸãã
- ããã¯æ©æ§ïŒ ãã¥ãŒããã¯ã¹ãã»ããã©ã®ãããªæè¡ã§ãäžåºŠã«äžã€ã®ã¹ã¬ããã®ã¿ãããŒã¿æ§é ã®ç¹å®ã®éšåã«ã¢ã¯ã»ã¹ã§ããããã«ããåæå€æŽãé²ããŸãã
- ããã¯ããªãŒããŒã¿æ§é ïŒ ã¢ãããã¯æäœãšå·§åŠãªã¢ã«ãŽãªãºã ã䜿çšããŠããŒã¿ã®äžè²«æ§ãä¿èšŒããæç€ºçãªããã¯ãå®å šã«åé¿ããé«åºŠãªããŒã¿æ§é ã§ãã
䞊è¡ãããã®å ·äœçãªå®è£ 詳现ã¯ãããã°ã©ãã³ã°èšèªãåºç€ãšãªãããŒããŠã§ã¢ã¢ãŒããã¯ãã£ã«ãã£ãŠç°ãªããŸããJavaScriptã§ã¯ãèšèªã®ã·ã³ã°ã«ã¹ã¬ããã®æ§è³ªã®ãããçã«äžŠè¡ãªããŒã¿æ§é ãå®è£ ããããšã¯å°é£ã§ããããããWeb Workerãéåææäœã®ãããªæè¡ãšãé©åãªåæã¡ã«ããºã ã䜵çšããããšã§ãäžŠè¡æ§ãã·ãã¥ã¬ãŒãããããšãã§ããŸãã
Web Workerã«ããJavaScriptã§ã®äžŠè¡æ§ã®ã·ãã¥ã¬ãŒã·ã§ã³
Web Workerã¯ãJavaScriptã³ãŒããå¥ã®ã¹ã¬ããã§å®è¡ããæ¹æ³ãæäŸãããã©ãŠã¶ç°å¢ã§äžŠè¡æ§ãã·ãã¥ã¬ãŒãããããšãå¯èœã«ããŸããMapã«æ ŒçŽãããå€§èŠæš¡ãªããŒã¿ã»ããã«å¯ŸããŠãèšç®éã®å€ãæäœãå®è¡ãããäŸãèããŠã¿ãŸãããã
äŸïŒWeb Workerãšå ±æMapã«ãã䞊åããŒã¿åŠç
ãŠãŒã¶ãŒããŒã¿ãå«ãMapããããååœããšã®ãŠãŒã¶ãŒã®å¹³å幎霢ãèšç®ããããšããŸããããŒã¿ãè€æ°ã®Web Workerã«åå²ããåã¯ãŒã«ãŒã«ããŒã¿ã®ãµãã»ããã䞊è¡ããŠåŠçãããããšãã§ããŸãã
ã¡ã€ã³ã¹ã¬ãã (index.html ãŸã㯠main.js):
// å€§èŠæš¡ãªãŠãŒã¶ãŒããŒã¿ã®Mapãäœæ
const userData = new Map();
for (let i = 0; i < 10000; i++) {
const country = ['USA', 'Canada', 'UK', 'Germany', 'France'][i % 5];
userData.set(i, { age: Math.floor(Math.random() * 60) + 18, country });
}
// åã¯ãŒã«ãŒçšã«ããŒã¿ããã£ã³ã¯ã«åå²
const numWorkers = 4;
const chunkSize = Math.ceil(userData.size / numWorkers);
const dataChunks = [];
let i = 0;
for (let j = 0; j < numWorkers; j++) {
const chunk = new Map();
let count = 0;
for (; i < userData.size && count < chunkSize; i++) {
chunk.set(i, userData.get(i));
count++;
}
dataChunks.push(chunk);
}
// Web Workerãäœæ
const workers = [];
const results = new Map();
let completedWorkers = 0;
for (let i = 0; i < numWorkers; i++) {
const worker = new Worker('worker.js');
workers.push(worker);
worker.onmessage = (event) => {
const { countryAverages } = event.data;
// ã¯ãŒã«ãŒããã®çµæãããŒãž
for (const [country, average] of countryAverages) {
if (results.has(country)) {
const existing = results.get(country);
results.set(country, { sum: existing.sum + average.sum, count: existing.count + average.count });
} else {
results.set(country, average);
}
}
completedWorkers++;
if (completedWorkers === numWorkers) {
// ãã¹ãŠã®ã¯ãŒã«ãŒãçµäº
const finalAverages = new Map();
for (const [country, data] of results) {
finalAverages.set(country, data.sum / data.count);
}
console.log('Final Averages:', finalAverages);
}
worker.terminate(); // 䜿çšåŸã«ã¯ãŒã«ãŒãçµäº
};
worker.onerror = (error) => {
console.error('Worker error:', error);
};
// ã¯ãŒã«ãŒã«ããŒã¿ãã£ã³ã¯ãéä¿¡
worker.postMessage({ data: Array.from(dataChunks[i]) });
}
Web Worker (worker.js):
self.onmessage = (event) => {
const { data } = event.data;
const userData = new Map(data);
const countryAverages = new Map();
for (const [id, user] of userData) {
const { country, age } = user;
if (countryAverages.has(country)) {
const existing = countryAverages.get(country);
countryAverages.set(country, { sum: existing.sum + age, count: existing.count + 1 });
} else {
countryAverages.set(country, { sum: age, count: 1 });
}
}
self.postMessage({ countryAverages: countryAverages });
};
ãã®äŸã§ã¯ãåWeb Workerã¯ç¬èªã®ç¬ç«ããããŒã¿ã®ã³ããŒãåŠçããŸããããã«ãããæç€ºçãªããã¯ãåæã¡ã«ããºã ã®å¿ èŠæ§ãåé¿ãããŸããããããã¯ãŒã«ãŒã®æ°ãããŒãžæäœã®è€éããé«ãå Žåãã¡ã€ã³ã¹ã¬ããã§ã®çµæã®ããŒãžãäŸç¶ãšããŠããã«ããã¯ã«ãªãå¯èœæ§ããããŸãããã®ãããªå Žåãæ¬¡ã®ãããªæè¡ãæ€èšããããšãã§ããŸãïŒ
- ã¢ãããã¯ãªæŽæ°ïŒ éèšæäœãã¢ãããã¯ã«å®è¡ã§ããå ŽåãSharedArrayBufferãšAtomicsæäœã䜿çšããŠãã¯ãŒã«ãŒããçŽæ¥å ±æããŒã¿æ§é ãæŽæ°ããããšãã§ããŸãããã ãããã®ã¢ãããŒãã¯æ éãªåæãå¿ èŠã§ãããæ£ããå®è£ ããã®ã¯è€éã«ãªãå¯èœæ§ããããŸãã
- ã¡ãã»ãŒãžããã·ã³ã°ïŒ ã¡ã€ã³ã¹ã¬ããã§çµæãããŒãžãã代ããã«ãã¯ãŒã«ãŒå士ã§éšåçãªçµæãéãåããããŒãžã®è² è·ãè€æ°ã®ã¹ã¬ããã«åæ£ãããããšãã§ããŸãã
éåææäœãšããã¯ã«ããåºæ¬çãªäžŠè¡ãããã®å®è£
Web Workerã¯çã®äžŠåæ§ãæäŸããŸãããåäžã¹ã¬ããå ã§éåææäœãšããã¯æ©æ§ã䜿çšããŠäžŠè¡æ§ãã·ãã¥ã¬ãŒãããããšãã§ããŸãããã®ã¢ãããŒãã¯ãI/OããŠã³ããªæäœãäžè¬çãªNode.jsç°å¢ã§ç¹ã«æçšã§ãã
以äžã«ãã·ã³ãã«ãªããã¯æ©æ§ã䜿çšããŠå®è£ ãããåºæ¬çãªäžŠè¡ãããã®äŸã瀺ããŸãïŒ
class ConcurrentMap {
constructor() {
this.map = new Map();
this.lock = false; // ããŒã«å€ã®ãã©ã°ã䜿çšããã·ã³ãã«ãªããã¯
}
async get(key) {
while (this.lock) {
// ããã¯ãè§£æŸãããã®ãåŸ
ã€
await new Promise((resolve) => setTimeout(resolve, 0));
}
return this.map.get(key);
}
async set(key, value) {
while (this.lock) {
// ããã¯ãè§£æŸãããã®ãåŸ
ã€
await new Promise((resolve) => setTimeout(resolve, 0));
}
this.lock = true; // ããã¯ãååŸ
try {
this.map.set(key, value);
} finally {
this.lock = false; // ããã¯ãè§£æŸ
}
}
async delete(key) {
while (this.lock) {
// ããã¯ãè§£æŸãããã®ãåŸ
ã€
await new Promise((resolve) => setTimeout(resolve, 0));
}
this.lock = true; // ããã¯ãååŸ
try {
this.map.delete(key);
} finally {
this.lock = false; // ããã¯ãè§£æŸ
}
}
}
// 䜿çšäŸ
async function example() {
const concurrentMap = new ConcurrentMap();
// 䞊è¡ã¢ã¯ã»ã¹ãã·ãã¥ã¬ãŒã
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(
(async () => {
await concurrentMap.set(i, `Value ${i}`);
console.log(`Set ${i}:`, await concurrentMap.get(i));
await concurrentMap.delete(i);
console.log(`Deleted ${i}:`, await concurrentMap.get(i));
})()
);
}
await Promise.all(promises);
console.log('Finished!');
}
example();
ãã®äŸã§ã¯ãã·ã³ãã«ãªããŒã«å€ã®ãã©ã°ãããã¯ãšããŠäœ¿çšããŠããŸããMapã«ã¢ã¯ã»ã¹ãŸãã¯å€æŽããåã«ãåéåææäœã¯ããã¯ãè§£æŸãããã®ãåŸ
ã¡ãããã¯ãååŸããæäœãå®è¡ãããããŠããã¯ãè§£æŸããŸããããã«ãããäžåºŠã«äžã€ã®æäœããMapã«ã¢ã¯ã»ã¹ã§ããªãããšãä¿èšŒãããç«¶åç¶æ
ãé²ãããŸãã
éèŠãªæ³šæïŒ ããã¯éåžžã«åºæ¬çãªäŸã§ãããæ¬çªç°å¢ã§äœ¿çšããã¹ãã§ã¯ãããŸãããéåžžã«éå¹ççã§ããããããããã¯ã®ãããªåé¡ãçºçããããã§ããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã»ããã©ããã¥ãŒããã¯ã¹ãªã©ãããå ç¢ãªããã¯æ©æ§ã䜿çšããå¿ èŠããããŸãã
課é¡ãšèæ ®äºé
JavaScriptã§äžŠè¡ããããå®è£ ããã«ã¯ãããã€ãã®èª²é¡ããããŸãïŒ
- JavaScriptã®ã·ã³ã°ã«ã¹ã¬ããã®æ§è³ªïŒ JavaScriptã¯åºæ¬çã«ã·ã³ã°ã«ã¹ã¬ããã§ãããéæã§ããçã®äžŠåæ§ã®åºŠåããå¶éãããŸããWeb Workerã¯ãã®å¶éãåé¿ããæ¹æ³ãæäŸããŸããã远å ã®è€éãã䌎ããŸãã
- åæã®ãªãŒããŒãããïŒ ããã¯æ©æ§ã¯ãªãŒããŒãããã䌎ããæ éã«å®è£ ããªããšäžŠè¡æ§ã®ããã©ãŒãã³ã¹äžã®å©ç¹ãçžæ®ºããŠããŸãå¯èœæ§ããããŸãã
- è€éãïŒ äžŠè¡ããŒã¿æ§é ã®èšèšãšå®è£ ã¯æ¬è³ªçã«è€éã§ãããäžŠè¡æ§ã®æŠå¿µãšæœåšçãªèœãšã穎ã«ã€ããŠæ·±ãçè§£ãå¿ èŠã§ãã
- ãããã°ïŒ 䞊è¡ã³ãŒãã®ãããã°ã¯ã䞊è¡å®è¡ã®é決å®çãªæ§è³ªã®ãããã·ã³ã°ã«ã¹ã¬ããã³ãŒãã®ãããã°ãããèããå°é£ã«ãªãããšããããŸãã
JavaScriptã«ããã䞊è¡ãããã®ãŠãŒã¹ã±ãŒã¹
課é¡ã¯ãããã®ã®ã䞊è¡ãããã¯ããã€ãã®ã·ããªãªã§äŸ¡å€ããããŸãïŒ
- ãã£ãã·ã³ã°ïŒ è€æ°ã®ã¹ã¬ãããéåæã³ã³ããã¹ãããã¢ã¯ã»ã¹ããã³æŽæ°ã§ãã䞊è¡ãã£ãã·ã¥ã®å®è£ ã
- ããŒã¿éçŽïŒ ãªã¢ã«ã¿ã€ã ã®ããŒã¿åæã¢ããªã±ãŒã·ã§ã³ãªã©ãè€æ°ã®ãœãŒã¹ããã®ããŒã¿ã䞊è¡ããŠéçŽããã
- ã¿ã¹ã¯ãã¥ãŒïŒ è€æ°ã®ã¯ãŒã«ãŒã«ãã£ãŠäžŠè¡ããŠåŠçã§ããã¿ã¹ã¯ã®ãã¥ãŒã管çããã
- ã²ãŒã éçºïŒ ãã«ããã¬ã€ã€ãŒã²ãŒã ã§ã²ãŒã ã®ç¶æ ã䞊è¡ããŠç®¡çããã
䞊è¡ãããã®ä»£æ¿æ¡
䞊è¡ããããå®è£ ããåã«ã代æ¿ã¢ãããŒããããé©ããŠãããã©ãããæ€èšããŠãã ããïŒ
- ã€ãã¥ãŒã¿ãã«ïŒäžå€ïŒããŒã¿æ§é ïŒ ã€ãã¥ãŒã¿ãã«ããŒã¿æ§é ã¯ãããŒã¿ãäœæãããåŸã«å€æŽã§ããªãããšãä¿èšŒããããšã§ãããã¯ã®å¿ èŠæ§ãæé€ã§ããŸããImmutable.jsã®ãããªã©ã€ãã©ãªã¯ãJavaScriptçšã®ã€ãã¥ãŒã¿ãã«ããŒã¿æ§é ãæäŸããŸãã
- ã¡ãã»ãŒãžããã·ã³ã°ïŒ ã¹ã¬ããéãéåæã³ã³ããã¹ãéã§éä¿¡ããããã«ã¡ãã»ãŒãžããã·ã³ã°ã䜿çšãããšãå ±æã®å¯å€ç¶æ ã®å¿ èŠæ§ãå®å šã«åé¿ã§ããŸãã
- èšç®ã®ãªãããŒãïŒ èšç®éã®å€ãã¿ã¹ã¯ãããã¯ãšã³ããµãŒãã¹ãã¯ã©ãŠã颿°ã«ãªãããŒãããããšã§ãã¡ã€ã³ã¹ã¬ãããè§£æŸããã¢ããªã±ãŒã·ã§ã³ã®å¿çæ§ãåäžãããããšãã§ããŸãã
çµè«
䞊è¡ãããã¯ãJavaScriptã«ããã䞊åããŒã¿æ§é æäœã®ããã®åŒ·åãªããŒã«ãæäŸããŸããJavaScriptã®ã·ã³ã°ã«ã¹ã¬ããã®æ§è³ªãšäžŠè¡æ§ã®è€éãããå®è£ ã«ã¯èª²é¡ããããŸããããã«ãã¹ã¬ãããéåæç°å¢ã§ã®ããã©ãŒãã³ã¹ãå€§å¹ ã«åäžãããããšãã§ããŸãããã¬ãŒããªããçè§£ãã代æ¿ã¢ãããŒããæ éã«æ€èšããããšã§ãéçºè ã¯äžŠè¡ããããæŽ»çšããŠãããå¹ççã§ã¹ã±ãŒã©ãã«ãªJavaScriptã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã
䞊è¡ã³ãŒããæ£ããæ©èœããããã©ãŒãã³ã¹äžã®å©ç¹ãåæã®ãªãŒããŒããããäžåã£ãŠããããšã確èªããããã«ã培åºçã«ãã¹ããšãã³ãããŒã¯ãè¡ãããšãå¿ããªãã§ãã ããã
ãããªãæ¢æ±
- Web Workers API: MDN Web Docs
- SharedArrayBuffer and Atomics: MDN Web Docs
- Immutable.js: å ¬åŒãµã€ã